/********************************************************************************
* Copyright (c) 2009, Matteo Pelati (matteo.pelati@gmail.com)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in the
*       documentation and/or other materials provided with the distribution.
*     * Neither the name of the <organization> nor the
*       names of its contributors may be used to endorse or promote products
*       derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Matteo Pelati ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**************************************************************************************/

#include "stdafx.h"
#include <iostream>
#include <exception>


#include "DbEnvironment.h"
#include "DbXmlManager.h"
#include "DbXmlContainer.h"
#include "DbException.h"
#include "DbXmlException.h"
#include "DbXmlIndexSpecification.h"
#include "DbXmlValue.h"


namespace BerkeleyDB { namespace Xml
{

	DbXmlDocument^ DbXmlContainer::GetDocument(String^ name, DbXmlDocumentFlags flags)
	{
		try
		{
			CLRSTR2STDSTR(cname, name);
			return gcnew DbXmlDocument(this, n_cont->getDocument(cname, (u_int32_t)flags));
		}
		rethrowDbXmlException();
	}

	DbXmlDocument^ DbXmlContainer::GetDocument(DbXmlTransaction^ txn, String^ name, DbXmlDocumentFlags flags)
	{
		if (txn == nullptr) return GetDocument(name, flags);
		try
		{
			CLRSTR2STDSTR(cname, name);
			return gcnew DbXmlDocument(this, n_cont->getDocument(*(txn->GetInnerObject()), cname, (u_int32_t)flags));
		}
		rethrowDbXmlException();
	}

	void DbXmlContainer::PutDocument(DbXmlDocument^ doc, DbXmlUpdateContext^ ctx, DbXmlDocumentCreateFlags flags)
	{
		try
		{
			n_cont->putDocument(*(doc->GetInnerObject()), *(ctx->GetInnerObject()), (u_int32_t) flags);
		}
		rethrowDbXmlException();
	}
	
	
	void DbXmlContainer::PutDocument(DbXmlTransaction^ txn, DbXmlDocument^ doc, DbXmlUpdateContext^ ctx, DbXmlDocumentCreateFlags flags)
	{
		if (txn == nullptr)  
		{
			PutDocument(doc, ctx, flags);
			return;
		}

		try
		{
			n_cont->putDocument(*(txn->GetInnerObject()), *(doc->GetInnerObject()), *(ctx->GetInnerObject()), (u_int32_t) flags);
		}
		rethrowDbXmlException();
	}
	
	void DbXmlContainer::PutDocument(String^ name, String^ content, DbXmlUpdateContext^ ctx, DbXmlDocumentCreateFlags flags)
	{
		try
		{
			CLRSTR2STDSTR(cname, name);
			CLRSTR2STDSTR(ccontent, content);
			n_cont->putDocument(cname, ccontent, *(ctx->GetInnerObject()), (u_int32_t) flags);
		}
		rethrowDbXmlException();
	}
	
	void DbXmlContainer::PutDocument(DbXmlTransaction^ txn, String^ name, String^ content, DbXmlUpdateContext^ ctx, DbXmlDocumentCreateFlags flags)
	{
		if (txn == nullptr)  
		{
			PutDocument(name, content, ctx, flags);
			return;
		}
		try
		{
			CLRSTR2STDSTR(cname, name);
			CLRSTR2STDSTR(ccontent, content);
			n_cont->putDocument(*(txn->GetInnerObject()), cname, ccontent, *(ctx->GetInnerObject()), (u_int32_t) flags);
		}
		rethrowDbXmlException();
	}

	void DbXmlContainer::DeleteDocument(String^ name, DbXmlUpdateContext^ ctx)
	{
		try
		{
			CLRSTR2STDSTR(cname, name);
			n_cont->deleteDocument(cname, *(ctx->GetInnerObject()));
		}
		rethrowDbXmlException();
	}
	
	void DbXmlContainer::DeleteDocument(DbXmlDocument^ doc, DbXmlUpdateContext^ ctx)
	{
		try
		{
			n_cont->deleteDocument(*(doc->GetInnerObject()), *(ctx->GetInnerObject()));
		}
		rethrowDbXmlException();
	}
	
	void DbXmlContainer::DeleteDocument(DbXmlTransaction^ txn, String^ name, DbXmlUpdateContext^ ctx)
	{
		if (txn == nullptr)  
		{
			DeleteDocument(txn, name, ctx);
			return;
		}
		try
		{
			CLRSTR2STDSTR(cname, name);
			n_cont->deleteDocument(*(txn->GetInnerObject()), cname, *(ctx->GetInnerObject()));
		}
		rethrowDbXmlException();
	}
	
	void DbXmlContainer::DeleteDocument(DbXmlTransaction^ txn, DbXmlDocument^ doc, DbXmlUpdateContext^ ctx)
	{
		if (txn == nullptr)  
		{
			DeleteDocument(txn, doc, ctx);
			return;
		}
		try
		{
			n_cont->deleteDocument(*(txn->GetInnerObject()), *(doc->GetInnerObject()), *(ctx->GetInnerObject()));
		}
		rethrowDbXmlException();
	}

	void DbXmlContainer::UpdateDocument(DbXmlDocument^ doc, DbXmlUpdateContext^ ctx)
	{
		try
		{
			n_cont->deleteDocument(*(doc->GetInnerObject()), *(ctx->GetInnerObject()));
		}
		rethrowDbXmlException();
	}
	
	void DbXmlContainer::UpdateDocument(DbXmlTransaction^ txn, DbXmlDocument^ doc, DbXmlUpdateContext^ ctx)
	{
		if (txn == nullptr)  
		{
			UpdateDocument(doc, ctx);
			return;
		}
		try
		{
			n_cont->deleteDocument(*(txn->GetInnerObject()), *(doc->GetInnerObject()), *(ctx->GetInnerObject()));
		}
		rethrowDbXmlException();
	}

	void DbXmlContainer::AddAlias(String^ name)
	{
		try
		{
			CLRSTR2STDSTR(cname, name);
			n_cont->addAlias(cname);
		}
		rethrowDbXmlException();
	}

	bool DbXmlContainer::RemoveAlias(String^ name)
	{
		try
		{
			CLRSTR2STDSTR(cname, name);
			return n_cont->removeAlias(cname);
		}
		rethrowDbXmlException();
	}

	void DbXmlContainer::AddIndex(String^ uri, String^ name, String^ index, DbXmlUpdateContext^ ctx)
	{
		try
		{
			CLRSTR2STDSTR(curi, uri);
			CLRSTR2STDSTR(cname, name);
			CLRSTR2STDSTR(cindex, index);
			n_cont->addIndex(curi, cname, cindex, *(ctx->GetInnerObject()));
		}
		rethrowDbXmlException();
	}
	
	void DbXmlContainer::AddIndex(DbXmlTransaction^ txn, String^ uri, String^ name, String^ index, DbXmlUpdateContext^ ctx)
	{
		if (txn == nullptr)  
		{
			AddIndex(uri, name, index, ctx);
			return;
		}
		try
		{
			CLRSTR2STDSTR(curi, uri);
			CLRSTR2STDSTR(cname, name);
			CLRSTR2STDSTR(cindex, index);
			n_cont->addIndex(*(txn->GetInnerObject()), curi, cname, cindex, *(ctx->GetInnerObject()));
		}
		rethrowDbXmlException();
	}
	
	void DbXmlContainer::AddIndex(String^ uri, String^ name, DbXmlIndexSpecificationFlags type, DbXmlValueType syntax, DbXmlUpdateContext^ ctx)
	{
		try
		{
			CLRSTR2STDSTR(curi, uri);
			CLRSTR2STDSTR(cname, name);
			n_cont->addIndex(curi, cname, (XmlIndexSpecification::Type) type, (XmlValue::Type) syntax, *(ctx->GetInnerObject())); 
		}
		rethrowDbXmlException();
	}
	
	void DbXmlContainer::AddIndex(DbXmlTransaction^ txn, String^ uri, String^ name, DbXmlIndexSpecificationFlags type, DbXmlValueType syntax, DbXmlUpdateContext^ ctx)
	{
		if (txn == nullptr)  
		{
			AddIndex(uri, name, type, syntax, ctx);
			return;
		}
		try
		{
			CLRSTR2STDSTR(curi, uri);
			CLRSTR2STDSTR(cname, name);
			n_cont->addIndex(*(txn->GetInnerObject()), curi, cname, (XmlIndexSpecification::Type) type, (XmlValue::Type) syntax, *(ctx->GetInnerObject())); 
		}
		rethrowDbXmlException();
	}

	void DbXmlContainer::AddDefaultIndex(String^ index, DbXmlUpdateContext^ ctx)
	{
		try
		{
			CLRSTR2STDSTR(cindex, index);
			n_cont->addDefaultIndex(cindex, *(ctx->GetInnerObject())); 
		}
		rethrowDbXmlException();
	}
	
	void DbXmlContainer::AddDefaultIndex(DbXmlTransaction^ txn, String^ index, DbXmlUpdateContext^ ctx)
	{
		if (txn == nullptr)  
		{
			AddDefaultIndex(index, ctx);
			return;
		}
		try
		{
			CLRSTR2STDSTR(cindex, index);
			n_cont->addDefaultIndex(*(txn->GetInnerObject()), cindex, *(ctx->GetInnerObject())); 
		}
		rethrowDbXmlException();
	}

	void DbXmlContainer::ReplaceDefaultIndex(String^ index, DbXmlUpdateContext^ ctx)
	{
		try
		{
			CLRSTR2STDSTR(cindex, index);
			n_cont->replaceDefaultIndex(cindex, *(ctx->GetInnerObject())); 
		}
		rethrowDbXmlException();
	}
	
	void DbXmlContainer::ReplaceDefaultIndex(DbXmlTransaction^ txn, String^ index, DbXmlUpdateContext^ ctx)
	{
		if (txn == nullptr)  
		{
			ReplaceDefaultIndex(index, ctx);
			return;
		}
		try
		{
			CLRSTR2STDSTR(cindex, index);
			n_cont->replaceDefaultIndex(*(txn->GetInnerObject()), cindex, *(ctx->GetInnerObject())); 
		}
		rethrowDbXmlException();
	}

	void DbXmlContainer::DeleteIndex(String^ uri, String^ name, String^ index, DbXmlUpdateContext^ ctx)
	{
		try
		{
			CLRSTR2STDSTR(curi, uri);
			CLRSTR2STDSTR(cname, name);
			CLRSTR2STDSTR(cindex, index);
			n_cont->deleteIndex(curi, cname, cindex, *(ctx->GetInnerObject()));
		}
		rethrowDbXmlException();
	}
	
	void DbXmlContainer::DeleteIndex(DbXmlTransaction^ txn, String^ uri, String^ name, String^ index, DbXmlUpdateContext^ ctx)
	{
		if (txn == nullptr)  
		{
			DeleteIndex(uri, name, index, ctx);
			return;
		}
		try
		{
			CLRSTR2STDSTR(curi, uri);
			CLRSTR2STDSTR(cname, name);
			CLRSTR2STDSTR(cindex, index);
			n_cont->deleteIndex(*(txn->GetInnerObject()), curi, cname, cindex, *(ctx->GetInnerObject()));
		}
		rethrowDbXmlException();
	}

	DbXmlDocumentCollection^ DbXmlContainer::GetAllDocuments(DbXmlDocumentFlags flags)
	{
		try
		{
			return gcnew DbXmlDocumentCollection(this, n_cont->getAllDocuments((u_int32_t) flags), nullptr, nullptr);
		}
		rethrowDbXmlException();
	}
	
	DbXmlDocumentCollection^ DbXmlContainer::GetAllDocuments(DbXmlTransaction^ txn, DbXmlDocumentFlags flags)
	{
		if (txn == nullptr)  
			return GetAllDocuments(flags);
			
		try
		{
			return gcnew DbXmlDocumentCollection(this, n_cont->getAllDocuments(*(txn->GetInnerObject()), (u_int32_t) flags), txn, nullptr);
		}
		rethrowDbXmlException();
	}

	DbXmlIndexSpecification^ DbXmlContainer::GetIndexSpecification()
	{
		try
		{
			return gcnew DbXmlIndexSpecification(this, n_cont->getIndexSpecification());
		}
		rethrowDbXmlException();
	}

	DbXmlIndexSpecification^ DbXmlContainer::GetIndexSpecification(DbXmlTransaction^ txn, bool writeLock)
	{
		try
		{
			u_int32_t wlFlag = writeLock ? DB_RMW : 0;
			return gcnew DbXmlIndexSpecification(this, n_cont->getIndexSpecification(*(txn->GetInnerObject()), wlFlag));
		}
		rethrowDbXmlException();
	}

	DbXmlValue^ DbXmlContainer::GetNode(String^ nodeHandle, DbXmlDocumentFlags flags)
	{
		try
		{
			CLRSTR2STDSTR(cnodeHandle, nodeHandle);
			return gcnew DbXmlValue(this, n_cont->getNode(cnodeHandle, (u_int32_t) flags), nullptr, nullptr);
		}
		rethrowDbXmlException();
	}
	
	DbXmlValue^ DbXmlContainer::GetNode(DbXmlTransaction^ txn, String^ nodeHandle, DbXmlDocumentFlags flags)
	{
		if (txn == nullptr) return GetNode(nodeHandle, flags);
		try
		{
			CLRSTR2STDSTR(cnodeHandle, nodeHandle);
			return gcnew DbXmlValue(this, n_cont->getNode(*(txn->GetInnerObject()), cnodeHandle, (u_int32_t) flags), txn, nullptr);
		}
		rethrowDbXmlException();
	}

	void DbXmlContainer::ReplaceIndex(String^ uri, String^ name, String^ index, DbXmlUpdateContext^ ctx)
	{
		try
		{
			CLRSTR2STDSTR(curi, uri);
			CLRSTR2STDSTR(cname, name);
			CLRSTR2STDSTR(cindex, index);
			n_cont->replaceIndex(curi, cname, cindex, *(ctx->GetInnerObject()));
		}
		rethrowDbXmlException();
	}
	
	void DbXmlContainer::ReplaceIndex(DbXmlTransaction^ txn, String^ uri, String^ name, String^ index, DbXmlUpdateContext^ ctx)
	{
		if (txn == nullptr)  
		{
			ReplaceIndex(uri, name, index, ctx);
			return;
		}
		try
		{
			CLRSTR2STDSTR(curi, uri);
			CLRSTR2STDSTR(cname, name);
			CLRSTR2STDSTR(cindex, index);
			n_cont->replaceIndex(*(txn->GetInnerObject()), curi, cname, cindex, *(ctx->GetInnerObject()));
		}
		rethrowDbXmlException();
	}

	void DbXmlContainer::SetIndexSpecification(DbXmlIndexSpecification^ index, DbXmlUpdateContext^ ctx)
	{
		try
		{
			n_cont->setIndexSpecification(*(index->GetInnerObject()), *(ctx->GetInnerObject()));
		}
		rethrowDbXmlException();
	}
	
	void DbXmlContainer::SetIndexSpecification(DbXmlTransaction^ txn, DbXmlIndexSpecification^ index, DbXmlUpdateContext^ ctx)
	{
		if (txn == nullptr) SetIndexSpecification(index, ctx);
		try
		{
			n_cont->setIndexSpecification(*(txn->GetInnerObject()), *(index->GetInnerObject()), *(ctx->GetInnerObject()));
		}
		rethrowDbXmlException();
	}


}}